package com.scs.application.modules.dept.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.entity.DataEntity;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.flow.FlowContext;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.DateUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.core.utils.UserUtils;
import com.scs.application.core.utils.UtilCommon;
import com.scs.application.modules.base.entity.Dept;
import com.scs.application.modules.base.entity.Matr;
import com.scs.application.modules.base.entity.Supplier;
import com.scs.application.modules.base.entity.Warehouse;
import com.scs.application.modules.base.mapper.DeptMapper;
import com.scs.application.modules.base.mapper.MatrMapper;
import com.scs.application.modules.base.mapper.SupplierMapper;
import com.scs.application.modules.base.service.WarehouseService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.base.util.MatrPassUtil;
import com.scs.application.modules.cfg.utils.ParameterUtils;
import com.scs.application.modules.dept.entity.Demand;
import com.scs.application.modules.dept.entity.DemandItem;
import com.scs.application.modules.dept.entity.DemandSum;
import com.scs.application.modules.dept.entity.DemandSumItem;
import com.scs.application.modules.dept.mapper.*;
import com.scs.application.modules.dept.service.DemandService;
import com.scs.application.modules.purchase.entity.Order;
import com.scs.application.modules.purchase.entity.OrderItem;
import com.scs.application.modules.purchase.enums.PoType;
import com.scs.application.modules.purchase.mapper.OrderItemMapper;
import com.scs.application.modules.purchase.mapper.OrderMapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
public class DemandServiceImpl extends BaseServiceImpl<DemandMapper, Demand> implements DemandService {

    @Autowired
    private DemandItemMapper demandItemMapper;

    @Autowired
    private MatrMapper matrMapper;

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private SupplierMapper supplierMapper;

    @Autowired
    private WarehouseService warehouseService;

    @Autowired
    private ApplyAutoMapper applyAutoMapper;

    @Autowired
    private DemandSumMapper demandSumMapper;
    @Autowired
    private DemandSumItemMapper demandSumItemMapper;

    @Autowired
    private MatrPassUtil matrPassUtil;

    @Override
    public boolean removeCascadeByIds(Collection<? extends Serializable> idList) {
        List<Demand> demands = this.list(Wrappers.<Demand>query().eq("id", idList));
        List<DemandItem> demandItemList = demandItemMapper.selectList(Wrappers.<DemandItem>query().in("demand_id", idList));
        demandItemMapper.delete(Wrappers.<DemandItem>query().in("demand_id", idList));
        boolean success = super.removeCascadeByIds(idList);
//        删除后对应 需求池删除
        List<String> applyAutoIds  = demandItemList.stream()
                .filter(demandItem -> StringUtils.isNotBlank(demandItem.getApplyAutoId()))
                .map(DemandItem::getApplyAutoId)
                .collect(Collectors.toList());
        if (applyAutoIds!=null && applyAutoIds.size()>0) {
            CommonService.updateApplyInfo(applyAutoIds,-1);
        }
        return success;
    }

    @Override
    public boolean saveOrUpdate(Demand entity) {

        if (StringUtils.isBlank(entity.getBusKey())) {
            entity.setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.DEPT_DEMAND_KEY));
        }
        return super.saveOrUpdate(entity);
    }

    @Override
    protected void beforeHandleFlowChange(FlowContext flowContext, Demand newEntity) {
        super.beforeHandleFlowChange(flowContext, newEntity);
        String buttonKey = flowContext.getButtonKey();
        // 提交审核，不允许空明细提交
        if ("submit".equalsIgnoreCase(buttonKey)) {
            Integer count = demandItemMapper.selectCount(Wrappers.<DemandItem>query().eq("demand_id", flowContext.getBusId()));
            if (count == null || count == 0) {
                throw new BusinessException("请添加明细后提交");
            }
            this.beforeSubmitCheck(newEntity,flowContext);
        }
        //流程节点控制--科室需求
        List<DemandItem> demandItems = demandItemMapper.selectList(Wrappers.<DemandItem>query().eq("demand_id", flowContext.getBusId()));
        matrPassUtil.ckeckMatrPass("demand", demandItems.stream().map(DemandItem::getMatrId).collect(Collectors.toList()));

    }

    /**
    * @Description： 提交计划前进行一些校验
    */
    private void beforeSubmitCheck(Demand demand,FlowContext flowContext){
        demand = baseMapper.selectById(demand.getId());
        //科室计划正常计划提交的日期限制 正常格式 num1,num2
        String deptDemandNormalDate = ParameterUtils.getString("dept_demand_normal_date");
        String nowDateYearMonth = DateUtils.format(DateUtils.now(),"yyyy-MM");
        if ("normal".equals(demand.getDemandType()) && StringUtils.isNotBlank(deptDemandNormalDate) && !"-1".equals(deptDemandNormalDate) && demand.getBusDate() != null) {
            String[] dateNumArr = deptDemandNormalDate.split(",");
            Calendar calender = Calendar.getInstance();
            calender.setTime(DateUtils.now());
            int demandDateMonth = calender.get(Calendar.MONTH);
            //长度为2，并且第一个数字小于等于第二个数字
            if(     dateNumArr.length == 2
                    && Integer.valueOf(dateNumArr[0]) <=  Integer.valueOf(dateNumArr[1])
                    && (demandDateMonth < Integer.valueOf(dateNumArr[0]) || demandDateMonth > Integer.valueOf(dateNumArr[1]))
            )
                throw new BusinessException("当前正常计划限制日期为%s号到%s号<br>请更改为临时计划或者紧急计划",dateNumArr[0],dateNumArr[1]);
        }

        //科室计划临时计划每科室每月的限制次数
        String deptDemandTempMax = ParameterUtils.getString("dept_demand_temp_max");
        if ("temp".equals(demand.getDemandType()) && StringUtils.isNotBlank(deptDemandTempMax) && !"-1".equals(deptDemandTempMax) ) {
            int deptDemandTempMaxInt = Integer.valueOf(deptDemandTempMax);

            int count = jdbcTemplate.queryForObject("select count(1) from dept_demand where" +
                    " dept_id ='"+demand.getDeptId()+"' and demand_type ='temp' and flow_status !='start' and date_format(bus_date,'%Y-%m') ='"+nowDateYearMonth+"'",Integer.class);
            if (count >= deptDemandTempMaxInt) throw new BusinessException("当前临时计划每科室每月的限制次数为%s<br>当月该科室已提交计划数量：%s<br>请更改为正常计划或者紧急计划",count,deptDemandTempMaxInt);

        }

    }

    @Override
    protected void afterHandleFlowChange(FlowContext flowContext, Demand newEntity) {
        super.afterHandleFlowChange(flowContext, newEntity);

        String buttonKey = flowContext.getButtonKey();
        if ("pass".equalsIgnoreCase(buttonKey)) {
            Demand demand = flowContext.getBusEntity();
            List<Order> orders = convertDemandToOrders(demand);

            flowContext.setHandledMsg(String.format("需求计划审核完成，共生成%d个采购订单", orders.size()));
            log.info("需求计划审核完成，共生成{}个采购订单", orders.size());
            log.info("采购单号分别为：{}", orders.stream().map(o -> o.getBusKey()).collect(Collectors.joining(",")));
        }

    }

    /**
     * 将需求转换为采购订单，依据 耗材所属供应商、购销、一物一码 的不同可能产生多张订单
     * 1.购销 一物一码 订单
     * 2.购销 非一物一码 订单
     * 3.代销 非一物一码 订单
     * 4.非代销 非一物一码 订单
     *
     * @param demand
     */
    @Override
    public List<Order> convertDemandToOrders(Demand demand) {
        String demandId = demand.getId();

        List<DemandItem> demandItems = demandItemMapper.selectList(Wrappers.<DemandItem>query().eq("demand_id", demandId));
        if (demandItems.isEmpty()) {
            throw new BusinessException("需求明细为空，转换采购订单失败");
        }
        //自动转采购：手动请领专购品（请领->需求计划->采购）流程中  需求->采购 需求转采购订单的耗材禁用过滤
        matrPassUtil.ckeckMatrPass("purchase", demandItems.stream().map(DemandItem::getMatrId).collect(Collectors.toList()));
        List<Matr> matrs = matrMapper.selectBatchIds(demandItems.stream().map(item -> item.getMatrId()).collect(Collectors.toList()));
        if (matrs.isEmpty()) {
            throw new BusinessException("需求明细所对应的耗材在系统中不存在，转换采购订单失败");
        }

        // key为耗材ID，value为耗材对象
        Map<String, Matr> matrMap = matrs.stream().collect(Collectors.toMap(matr -> matr.getId(), matr -> matr));

        // 依据供应商
        Map<OrderKey, List<DemandItem>> groupDemandItem = Maps.newHashMap();

        // 依据供应商、耗材购销/代销、一物一码属性、温度、耗材基础类型进行拆分
        for (DemandItem item : demandItems) {
            String matrId = item.getMatrId();

            Matr matr = matrMap.get(matrId);
            if (matr == null) {
                // 明细中的耗材 在 耗材表中 不存在
                throw new BusinessException("品名：%s，品规：%s 在耗材基础数据中不存在，转换采购订单失败",
                        item.getMatrName(), item.getMatrSpec());
            }
            Boolean flagConsignment = matr.getFlagConsignment();
            Boolean flagOmoc = matr.getFlagOmoc();

            OrderKey orderKey = new OrderKey(matr.getSupplierId(), flagConsignment, flagOmoc, matr.getTemperature(),UtilCommon.getStr(matr.getBaseType(),"matr"));
            List<DemandItem> items = groupDemandItem.get(orderKey);
            if (items == null) {
                items = Lists.newArrayList();
            }
            items.add(item);
            groupDemandItem.put(orderKey, items);

        }

        Warehouse warehouse =  warehouseService.getApplyWarehouseByWarehouseId(demand.getApplyWarehouseId());
        if(warehouse == null) {
            throw new BusinessException("未找到有效中心库房，转换采购订单失败");
        }
        ArrayList<Order> orders = Lists.newArrayList();
        for (OrderKey orderKey : groupDemandItem.keySet()) {
            Order order = convertDemandItemsToOrder(orderKey, demand, groupDemandItem.get(orderKey), warehouse);
            orders.add(order);
        }
        return orders;
    }

    private Order convertDemandItemsToOrder(OrderKey orderKey,
                                            Demand demand, List<DemandItem> demandItems, Warehouse warehouse) {

        String supplierId = orderKey.supplierId;
        Supplier supplier = supplierMapper.selectById(supplierId);
        if (supplier == null) {
            log.error("转换采购订单失败，需求单号：{}，供应商 {} 不存在", demand.getBusKey(), supplierId);
            throw new BusinessException("转换采购订单失败");
        }

        // 订单金额求和
        double sum = demandItems.stream().mapToDouble(o -> o.getAmount()).sum();
        // 根据一物一码和安全库存初分结算类型，调拨时再细分
        String orderCode = serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.PURCHASE_ORDER_KEY);
        String settlementType = orderKey.omoc ? GlobalConsts.SettlementType.usedSettlement : GlobalConsts.SettlementType.outSettlement;
        if (demand.getRefTable().equals(GlobalConsts.AUTO_REF_TABLE_SAFE)) {
            settlementType = GlobalConsts.SettlementType.usedSettlement;
        }
        String remarkPre = UtilCommon.getStringPre(demand.getRemark(), 100);
        String remark = UtilCommon.getStr(remarkPre, remarkPre);
        Order order = new Order();
        order.setBusKey(orderCode).setPurchaseType(orderKey.baseType).setTemperature(UtilCommon.getStr(orderKey.temperature,"无"))
                .setSupplierId(supplierId)
                .setSupplierName(supplier.getName())
                .setBusDate(new Date())
                .setBusUser(demand.getBusUser())
                .setDeptId(demand.getDeptIdTarget())
                .setDeptName(demand.getDeptNameTarget())
                .setDeptIdDemand(demand.getDeptId())
                .setDeptNameDemand(demand.getDeptName())
                .setFlagOmoc(orderKey.omoc)
                .setSettlementType(settlementType)
                .setPoType(orderKey.consignment ? PoType.CONSIGNMENT.getValue() : PoType.BUY.getValue())
                .setAmount(sum)
                .setFlagPushed(false)
                .setWarehouseId(warehouse.getId())
                .setWarehouseName(warehouse.getName())
                .setReagentTeamId(demand.getReagentTeamId())
        .setRefTable("dept_demand")
        .setRefId(demand.getId())
        .setRefKey(demand.getBusKey())
         .setRemark("[-"+remark+"-]"+String.format("由需求计划 %s 转换而来", demand.getBusKey()));
        ;
        if (demand.getDateLates() != null) {
            try {
                order.setDateLates(DateUtils.parse(demand.getDateLates(),"yyyy-MM-dd"));
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }else {
            order.setDateLates(DateUtils.addDays(new Date(), 3));
        }
        orderMapper.insert(order);

        for (DemandItem demandItem : demandItems) {
            OrderItem orderItem = new OrderItem();
            String[] ignoreFields = Arrays.asList(DataEntity.class.getDeclaredFields())
                    .stream().map(field -> field.getName()).collect(Collectors.toList()).toArray(new String[]{});
            BeanUtils.copyProperties(demandItem, orderItem, ignoreFields);
            orderItem.setOrderId(order.getId())
                    .setApplyAutoId(demandItem.getApplyAutoId())
                    .setRefId(demandItem.getId()).setApplyItemId(demandItem.getApplyItemId())
                    .setRemark(String.format("由需求计划 %s 转换而来", demand.getBusKey()))
            ;

            orderItemMapper.insert(orderItem);

            //更新需求明细状态
            CommonService.updateApplyItemStatus(demandItem.getApplyItemId(),false,null);
        }

        // 回写需求计划明细 采购订单ID 字段
        List<String> demandIds = demandItems.stream().map(o -> o.getId()).collect(Collectors.toList());
        demandItemMapper.update(null, Wrappers.<DemandItem>update().set("order_id", order.getId()).in("id", demandIds));

        return order;
    }

    @Override
    public DemandSum toDemandSum(List<Demand> demandAutos) {
        DemandSum demandSum = new DemandSum();
        String officeId = UserUtils.currentUser().getOfficeId();
        Dept dept = deptMapper.selectOne(new QueryWrapper<Dept>().eq("office_id", officeId));
        demandSum.setDeptId(dept.getId())
                .setDeptName(dept.getName())
                .setBusDate(new Date())
                .setBusUser(UserUtils.currentUser().getName())
                .setDemandSumType("0")
                .setBusKey(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.DEPT_DEMAND_SUM_KEY));
        demandSumMapper.insert(demandSum);
        Double amount = 0.00;
        for (Demand demandAuto : demandAutos) {
            amount += demandAuto.getAmount();
            DemandSumItem item = new DemandSumItem();
            item.setDemandId(demandAuto.getId())
                    .setDemandSumId(demandSum.getId());
            demandSumItemMapper.insert(item);
            demandAuto.setFlowStatus("collect");
            this.updateById(demandAuto);
        }
        demandSum.setAmount(amount);
        demandSumMapper.updateById(demandSum);
        return demandSum;
    }

    /**
     * 订单标识，用来作为转换订单时的标识
     */
    @EqualsAndHashCode
    @AllArgsConstructor
    public class OrderKey {
        private String supplierId;

        private boolean consignment;
        private boolean omoc;
        private String temperature;
        private String baseType;
    }
}
